package cn.xx.service.impl;

import cn.xx.dao.PromoDOMapper;
import cn.xx.dataobject.PromoDO;
import cn.xx.error.BusinessException;
import cn.xx.error.EmBusinessError;
import cn.xx.service.ItemService;
import cn.xx.service.PromoService;
import cn.xx.service.UserService;
import cn.xx.service.model.ItemModel;
import cn.xx.service.model.PromoModel;
import cn.xx.service.model.UserModel;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class PromoServiceImpl implements PromoService {

    @Autowired
    private PromoDOMapper promoDOMapper;

    @Autowired
    private ItemService itemService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserService userService;

    //根据itemId获取即将开始的或者正在进行的秒杀活动
    @Override
    public PromoModel getPromoByItemId(Integer itemId) {
        //获取商品对应的秒杀活动信息
        PromoDO promoDO = promoDOMapper.selectByItemId(itemId);

        //dataobject->model
        PromoModel promoModel = convertFromDataObject(promoDO);
        if (promoModel == null) {
            return null;
        }

        //判断当前时间是否秒杀活动即将开始或正在进行
        DateTime now = new DateTime();
        if (promoModel.getStartDate().isAfterNow()) { // 当前时间小于活动开始时间
            promoModel.setStatus(1); // 还未开始
        } else if (promoModel.getEndDate().isBeforeNow()) { // 当前时间大于活动开始时间
            promoModel.setStatus(3); // 已经结束
        } else {
            promoModel.setStatus(2); // 正在进行中
        }

        return promoModel;
    }

    @Override
    public void publishPromo(Integer promoId) {
        // 通过活动id获取活动
        PromoDO promoDO = promoDOMapper.selectByPrimaryKey(promoId);
        // 如果没有活动直接返回即可
        if (promoDO.getItemId() == null || promoDO.getItemId().intValue() == 0) {
            return;
        }
        // 根据商品id获取商品信息
        ItemModel itemModel = itemService.getItemById(promoDO.getItemId());

        // 将活动商品库存同步到redis中
        redisTemplate.opsForValue().set("promo_item_stock_" + itemModel.getId(), itemModel.getStock());
        // 将大闸的限制数字设置到redis中，比如有100个库存，我们可以发放500个令牌
        redisTemplate.opsForValue().set("promo_door_count_" + promoId, itemModel.getStock().intValue() * 5);
    }

    private PromoModel convertFromDataObject(PromoDO promoDO) {
        if (promoDO == null) {
            return null;
        }
        PromoModel promoModel = new PromoModel();
        BeanUtils.copyProperties(promoDO, promoModel);
        promoModel.setStartDate(new DateTime(promoDO.getStartDate()));
        promoModel.setEndDate(new DateTime(promoDO.getEndDate()));

        return promoModel;
    }

    // 生成秒杀用的令牌
    public String generateSecondKillToken(Integer promoId, Integer itemId, Integer userId) {
        // 判断是否库存已售罄，若对应的售罄key存在，则不能发放秒杀令牌
        if (redisTemplate.hasKey("promo_item_stock_invalid_" + itemId)) {
            return null;
        }

        //获取商品对应的秒杀活动信息
        PromoDO promoDO = promoDOMapper.selectByPrimaryKey(promoId);

        //dataobject->model
        PromoModel promoModel = convertFromDataObject(promoDO);
        if (promoModel == null) {
            return null;
        }

        // 判断当前时间是否秒杀活动即将开始或正在进行
        DateTime now = new DateTime();
        if (promoModel.getStartDate().isAfterNow()) { // 当前时间小于活动开始时间
            promoModel.setStatus(1); // 还未开始
        } else if (promoModel.getEndDate().isBeforeNow()) { // 当前时间大于活动开始时间
            promoModel.setStatus(3); // 已经结束
        } else {
            promoModel.setStatus(2); // 正在进行中
        }

        // 判断活动是否正在进行
        if (promoModel.getStatus().intValue() != 2) {
            return null;
        }

        // 判断商品信息是否存在
        ItemModel itemModel = itemService.getItemByIdInCache(itemId);
        if (itemModel == null) {
            return null;
        }

        // 判断用户信息是否存在
        UserModel userModel = userService.getUserByIdInCache(userId);
        if (userModel == null) {
            return null;
        }

        // 获取秒杀大闸的count数量（减完1之后的数量）
        Long result = redisTemplate.opsForValue().increment("promo_door_count_" + promoId, -1);
        if (result < 0) { // 如果减去后的数量小于0，则返回空
            return null;
        }

        // 生成token令牌，并且存入redis内，设置5分钟的有效期
        String token = UUID.randomUUID().toString().replace("-", "");

        redisTemplate.opsForValue().set("promo_token_" + promoId + "_userid_" + userId + "_itemid_" + itemId, token);
        // 设置令牌过期时间为5分钟
        redisTemplate.expire("promo_token_" + promoId + "_userid_" + userId + "_itemid_" + itemId, 5, TimeUnit.MINUTES);

        return token;
    }

}
